//@author A0097091Y

package crossoff.logic;

import java.io.IOException;

import crossoff.db.History;
import crossoff.db.Storage;
import crossoff.model.GUIobject;

public class CommandLogic {
	static String logMessage = null;
	private static final String[] WORDS_DELETE = { "delete", "del", "d", "crossoff" };
	private static final String[] WORDS_EDIT = { "edit", "e", "modify", "change" };
	private static final String[] WORDS_UNDO = { "undo", "u" };
	private static final String[] WORDS_REDO = { "redo", "r" };
	private static final String[] WORDS_EXIT = { "exit", "quit", "q" };
	private static final String[] WORDS_RESET = { "reset", "home", "h", "clear" };

	private static final String MESSAGE_INVALID_DELETE = "INVALID TASK NUMBER TO EDIT";
	private static final String MESSAGE_INVALID_EDIT = "INVALID TASK NUMBER TO EDIT";
	private static final String MESSAGE_TASK_ADDED = "TASK ADDED";
	private static final String MESSAGE_CONFIRM_UNDO = "UNDO LAST ACTION?";
	private static final String MESSAGE_CONFIRM_REDO = "REDO LAST ACTION?";
	private static final String MESSAGE_CONFIRM_SEARCH = "SEARCH FOR \"%1$s\"?";
	private static final String MESSAGE_CONFIRM_DELETE = "DELETE THIS TASK?";
	private static final String MESSAGE_CONFIRM_EDIT = "EDIT THIS TASK?";
	private static final String MESSAGE_CONFIRM_EXIT = "EXIT CROSSOFF?";

	public static GUIobject runCommand(String command, boolean store)
			throws IOException {

		String commandType = getFirstWord(command);
		commandType = commandType.toLowerCase();
		String[] commandSplit = command.split("\\s+");
		
		if (store == true) {

			if (checkCommandType(WORDS_UNDO, commandType) && commandSplit.length == 1) {
				return History.getInstance().executeUndo();
			}

			else if (checkCommandType(WORDS_REDO, commandType ) && commandSplit.length == 1) {
				return History.getInstance().executeRedo();
			}

			else if (commandType.equals("search") && commandSplit.length > 1) {
				return CommandSearchTask.searchTask(command);
			}

			else {
				History.getInstance().clearRedoStack();
			}

			if (checkCommandType(WORDS_DELETE, commandType)
					&& isValidDeleteCommand(command)) {
				if (isWithinRange(command)) {
					return CommandDelTask.deleteTask(command);
				} else {
					return new GUIobject(MESSAGE_INVALID_DELETE, "");
				}

			} else if (checkCommandType(WORDS_EDIT, commandType)
					&& isValidEditCommand(command)) {
				if (isWithinRange(command)) {
					return CommandEditTask.parseEditCommand(command);
				} else {
					return new GUIobject(MESSAGE_INVALID_EDIT, "");
				}
			} else if (checkCommandType(WORDS_RESET, commandType) && commandSplit.length == 1) {
				return new GUIobject();
			} else if (checkCommandType(WORDS_EXIT, commandType) && commandSplit.length == 1) {
				System.exit(0);
				return null;
			}

			else {
				logMessage = MESSAGE_TASK_ADDED;
				return CommandAddTask.addTask(command, store);
			}
		}

		else {

			if (checkCommandType(WORDS_UNDO, commandType)
					&& commandSplit.length == 1) {
				return new GUIobject(MESSAGE_CONFIRM_UNDO, "");
			}

			else if (checkCommandType(WORDS_REDO, commandType)
					&& commandSplit.length == 1) {
				return new GUIobject(MESSAGE_CONFIRM_REDO, "");
			}

			else if (commandType.equals("search") && commandSplit.length > 1) {
				return new GUIobject(String.format(MESSAGE_CONFIRM_SEARCH, command.substring(7)), "");
			}

			if (checkCommandType(WORDS_DELETE, commandType)
					&& isValidDeleteCommand(command)) {
				if (isWithinRange(command)) {
					return new GUIobject(MESSAGE_CONFIRM_DELETE, "",
							getCommandNumber(command));
				} else {
					return new GUIobject(MESSAGE_INVALID_DELETE, "");
				}

			} else if (checkCommandType(WORDS_EDIT, commandType)
					&& isValidEditCommand(command)) {
				if (isWithinRange(command)) {
					return new GUIobject(MESSAGE_CONFIRM_EDIT, "",
							getCommandNumber(command));
				} else {
					return new GUIobject(MESSAGE_INVALID_EDIT, "");
				}
			} else if (checkCommandType(WORDS_RESET, commandType)
					&& commandSplit.length == 1) {
				return new GUIobject();
			} else if (checkCommandType(WORDS_EXIT, commandType)
					&& commandSplit.length == 1) {
				return new GUIobject(MESSAGE_CONFIRM_EXIT, "");
			}

			else {
				logMessage = MESSAGE_TASK_ADDED;
				return CommandAddTask.addTask(command, store);
			}

		}

	}

	public static GUIobject runEditCommand(String command) throws IOException {

		return CommandEditTask.executeEditTask(command);
	}

	public static GUIobject addFloating(String command) throws IOException {

		return CommandAddTask.addFloating(command);
	}

	private static boolean isValidEditCommand(String command)
			throws NumberFormatException, IOException {
		String[] commandSplit = command.split("\\s+");

		if (commandSplit.length < 2) {
			return false;
		}

		if (!isNumber(commandSplit[1])) {
			return false;
		}

		return true;

	}

	private static boolean isValidDeleteCommand(String command)
			throws NumberFormatException, IOException {

		String[] commandSplit = command.split("\\s+");

		if (commandSplit.length != 2) {
			return false;
		}

		if (!isNumber(commandSplit[1])) {
			return false;
		}

		return true;

	}

	private static boolean isWithinRange(String command)
			throws NumberFormatException, IOException {

		String[] commandSplit = command.split("\\s+");

		if (Integer.parseInt(commandSplit[1]) == 0) {
			return false;
		}
		if (Integer.parseInt(commandSplit[1]) > Storage.getInstance().taskCache
				.size()) {
			return false;
		}

		return true;

	}

	private static String getFirstWord(String userCommand) {
		String commandTypeString = userCommand.trim().split("\\s+")[0];
		return commandTypeString;
	}

	// check if a String is an integer
	private static boolean isNumber(String string) {

		try {
			Integer.parseInt(string);
		} catch (NumberFormatException e) {
			return false;
		}

		return true;
	}

	private static int getCommandNumber(String command) {
		String[] commandSplit = command.split("\\s+");

		return Integer.parseInt(commandSplit[1]);
	}

	public static String getLogMessage() {
		return logMessage;
	}

	private static boolean checkCommandType(String[] Cache, String commandType) {
		for (int i = 0; i < Cache.length; i++) {
			if (Cache[i].equals(commandType))
				return true;
		}
		return false;
	}

}
